package com.zgg.files.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.zgg.base.BaseService;
import com.zgg.config.AliOssProperties;
import com.zgg.files.bean.OSSFile;
import com.zgg.files.dao.OSSFileMapper;
import com.zgg.files.service.UploadService;
import com.zgg.utils.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Service;

import java.io.File;
import java.util.*;


@Service
public class UploadServiceImpl extends BaseService implements UploadService {

    @Autowired
    private OSSFileMapper ossFileMapper;

    @Autowired
    private Environment env;

    @Autowired
    private RedisUtils redisUtils;

    private static final String tableCache = "oss_file:table";
    private static final String fileUrlCache = "oss_file:file_url_cache:";

    private static final int ttl = 60 * 60;

    private void tableExistAndCreate(String tableName) {
        if (!redisUtils.sismember(tableCache, tableName)) {
            int num = ossFileMapper.isTableExist(tableName);
            if (num == 0) {
                ossFileMapper.createTable(tableName);
            }
            redisUtils.sadd(tableCache, tableName);
        }
    }

    @Override
    public void uploadOSSFile(Map<String, String> fileNames, AliOssProperties aliOssProperties, JSONObject callbackJson) {
        aliOssProperties.setCallbackUrl(env.getProperty("ali.callbackUrl"));
        aliOssProperties.setCallbackHost(env.getProperty("ali.callbackHost"));

        Set<String> keySet = fileNames.keySet();
        for (String fileName : keySet) {
            String[] strings = fileName.split("/");
            redisUtils.set(AliOssProperties.uploadFileCache + strings[strings.length - 1],
                    fileNames.get(fileName) + "||" + callbackJson.getString("callbackBody"));
        }
        AliOssUtils.upLoadOSSFileList(fileNames, aliOssProperties, callbackJson);
    }

    @Override
    public void uploadFileInfo(List<OSSFile> ossFiles) {
        long startTime = System.currentTimeMillis();
        for (OSSFile ossFile : ossFiles) {
            tableExistAndCreate(tableNameAnalyze(ossFile.getId()));
            int num = ossFileMapper.saveOssFile(tableNameAnalyze(ossFile.getId()), ossFile);
        }
        long endTime = System.currentTimeMillis();
        logger.error("=============>>>>>>       线程id：【" + Thread.currentThread().getId() + "】 数据保存时间：【" + (endTime - startTime) + "】ms");
    }


    @Override
    @Deprecated
    public Map<String, String> uploadFileInfo(List<JSONObject> ossFileList, Integer userid, Integer usertype, String pathcode) {
        Map<String, String> imageIds = new HashMap<>();
        OSSFile ossFile = new OSSFile();
        for (JSONObject jsonObject : ossFileList) {
            String filePath = jsonObject.getString("fileName");
            // TODO: 2018/9/30 没有域名，没有上传回调接口，所以只能用这种形式返回数据结果并存库。后续需要将存库、删除临时文件的动作改为callback方式。
            ossFile.setId(UUIDUtils.getUUID());
            ossFile.setFpath(jsonObject.getString("ossPath"));
            ossFile.setFiletype(FileUtils.isImgFile(filePath) ? 1 : 2);
            ossFile.setSize(FileUtils.fileLengthByByte(filePath));
            ossFile.setFname(filePath);
            ossFile.setAddtime(new Date());
            ossFile.setStatus(0);

            ossFile.setAdduserid(userid);
            ossFile.setAddusertype(usertype);
            ossFile.setPathcode(pathcode);

            int num = ossFileMapper.saveOssFile(tableNameGenerate(), ossFile);
            //数据入库后删除临时文件
            if (num > 0) {
                FileUtils.removeFilePath(filePath);
            }
        }
        return imageIds;
    }

    @Override
    public File downOSSFile(OSSFile ossFile, AliOssProperties aliOssProperties) {
        String outFilePth = env.getProperty("ali.localUrl") + "down/";
        String filepath = AliOssUtils.downFileStream(ossFile, outFilePth, aliOssProperties);
        redisUtils.sadd(AliOssProperties.downFileCache, filepath);
        File file = new File(filepath);
        return file;
    }

    @Override
    public File downOSSFile(List<String> fileIds, AliOssProperties aliOssProperties) {
        String outFilePth = env.getProperty("ali.localUrl") + "down/";

        Map<String, List<String>> tableMap = new HashMap<>();
        for (String fileId : fileIds) {
            String tablename = tableNameAnalyze(fileId);
            if (tableMap.containsKey(tablename)) {
                tableMap.get(tablename).add(fileId);
            } else {
                List<String> fileIdList = new ArrayList<>();
                fileIdList.add(fileId);
                tableMap.put(tablename, fileIdList);
            }
            //tables.add();
        }
        //根据不同的id去不同的分表里查询数据并组合。
        List<OSSFile> filePaths = new ArrayList<>();
        Set<String> keySet = tableMap.keySet();
        for (String tableName : keySet) {
            List<OSSFile> ossFiles = ossFileMapper.getOSSFile(tableName, tableMap.get(tableName));
            filePaths.addAll(ossFiles);
        }

        File file = null;
        if (filePaths != null) {
            String filepath = AliOssUtils.downFileAndZip(filePaths, outFilePth, aliOssProperties);
            redisUtils.sadd(AliOssProperties.downFileCache, filepath);
            file = new File(filepath);
            if (filePaths.size() == fileIds.size()) {
                logger.error("=============>>>>>>    有文件查询失败");
            }
        }

        return file;
    }

    @Override
    public String getOSSFilePath(String fileId, AliOssProperties aliOssProperties) {
        String fileUrl = new String();
        if (redisUtils.exists(fileUrlCache + fileId)) {
            fileUrl = redisUtils.get(fileUrlCache + fileId);
        } else {
            OSSFile ossFile = findOssFileById(fileId);
            if (ossFile != null) {
                fileUrl = AliOssUtils.getImageUrl(ossFile.getFpath(), aliOssProperties);
                redisUtils.set(fileUrlCache + fileId, fileUrl, ttl);
            } else {
                logger.error("=======>>>>>   获取url失败!");
            }
        }
        return fileUrl;
    }

    @Override
    public int updateFileInfo(OSSFile ossFile) {
        int num = ossFileMapper.updateOSSFile(tableNameAnalyze(ossFile.getId()), ossFile);
        return num;
    }

    @Override
    public int deleteFileInfo(String id, AliOssProperties aliOssProperties) {
        OSSFile ossFile = ossFileMapper.findOSSFileById(tableNameAnalyze(id), id);
        int num = 0;
        if (ossFile != null) {
            AliOssUtils.delOssFile(ossFile.getFpath(), aliOssProperties);
            num = ossFileMapper.deleteOssFileById(tableNameAnalyze(id), id);
        }

        return num;
    }

    @Override
    public OSSFile findOssFileById(String id) {
        return ossFileMapper.findOSSFileById(tableNameAnalyze(id), id);
    }

    @Override
    public Map<String, String> getOssFileByIds(List<String> ids, AliOssProperties aliOssProperties) {
        Set tableNameSet = redisUtils.smembers(tableCache);
        Map<String, String> ossFilesMap = new HashMap<>();

        Map<String, List<String>> idsMap = new HashMap<>();
        List<String> idTemp = new ArrayList<>();
        for (String id : ids) {
            if (redisUtils.exists(fileUrlCache + id)) {
                ossFilesMap.put(id, redisUtils.get(fileUrlCache + id));
                idTemp.add(id);
            }
        }
        ids.removeAll(idTemp);
        idTemp = null;

        //根据不同的表名分成不同的id查询段
        for (Object object : tableNameSet) {
            String tableName = String.valueOf(object);
            List<String> temp = new ArrayList<>();
            for (String id : ids) {
                if (tableName.equals(tableNameAnalyze(id))) {
                    temp.add(id);
                }
            }
            ids.removeAll(temp);
            idsMap.put(tableName, temp);
        }

        //进行查询
        Set<String> tableKey = idsMap.keySet();
        for (String table : tableKey) {
            if (idsMap.get(table).size() > 0) {
                List<OSSFile> files = ossFileMapper.getOSSFile(table, idsMap.get(table));
                if (files.size() > 0) {
                    for (OSSFile file : files) {
                        String fileUrl = AliOssUtils.getImageUrl(file.getFpath(), aliOssProperties);
                        ossFilesMap.put(file.getId(), fileUrl);
                        redisUtils.set(fileUrlCache + file.getId(), fileUrl, ttl);
                    }
                }
            }
        }
        return ossFilesMap;
    }

    @Override
    public OSSFile findOssFileByPath(String ossFilePath) {
        return ossFileMapper.findOSSFileByPath(tableNameAnalyzeByPath(ossFilePath), ossFilePath);
    }


    private String tableName = "oss_files_";

    /**
     * 根据文件存储路径解析表名
     *
     * @param ossFilePath
     * @return
     */
    private String tableNameAnalyzeByPath(String ossFilePath) {
        if (ossFilePath != null) {
            String[] fixed = ossFilePath.split("/");
            if (fixed.length > 1) {
                return tableName + fixed[1];
            } else {
                return tableName + "2018";
            }
        } else {
            return "";
        }
    }

    /**
     * 根据id解析表名
     *
     * @param id
     * @return
     */
    private String tableNameAnalyze(String id) {
        if (id != null) {
            String[] fixed = id.split("-");
            if (fixed.length > 1) {
                return tableName + fixed[1];
            } else {
                return tableName + "2018";
            }
        } else {
            return "";
        }
    }

    /**
     * 根据年份生成表名
     *
     * @return
     */
    private String tableNameGenerate() {
        return tableName + DateUtils.getDateByFormat(new Date(), "yyyy");
    }

}
